//
//  MM_Http.m
//  MallManage_IOS
//
//  Created by 张浩 on 2023/9/19.
//

#import "MM_Http.h"
#import "MM_DB.h"

// 请求方式
typedef NS_ENUM(NSInteger, RequestType) {
    RequestTypeGet,
    RequestTypePost,
    RequestTypePut,
    RequestTypeDelete,
    RequestTypeUpLoadOne,
    RequestTypeUpLoadMore
};

static NSMutableArray *mm_requestTasks;
/* 断点续传的 path 和 op 存储 **/
static NSMutableArray *mm_downLoadPath;

#define KNOLogin  @"401"

@implementation MM_Http

+ (NSMutableArray *)allTasks {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (mm_requestTasks == nil) {
            mm_requestTasks = [[NSMutableArray alloc] init];
        }
    });
    return mm_requestTasks;
}

+ (NSMutableArray *)allDownLoadPathAndTask {
    
    /*  单例 数组 **/
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (mm_downLoadPath == nil) {
            mm_downLoadPath = [[NSMutableArray alloc] init];
        }
    });
    return mm_downLoadPath;
}

- (NSString *)returnServeErrorWithError:(NSError *)error {
    NSString *str = KMM_Domain_Status == 1 ? @"" : [error localizedDescription];
    return str;
}
#pragma mark -- 取消所有请求
+ (void)cancelAllRequest {
    @synchronized(self) {
        MMLog(@"%@", [self allTasks]);
        [[self allTasks] enumerateObjectsUsingBlock:^(NSURLSessionDataTask * _Nonnull task, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([task isKindOfClass:[NSURLSessionDataTask class]]) {
                MMLog(@"%@    取消了",task);
                [task cancel];
            }
        }];
        [[self allTasks] removeAllObjects];
    };
}

#pragma mark -- 取消某一个请求
+ (void)cancelRequestWithUrl:(NSString *)url {
    if (url == nil) {
        return;
    }
    @synchronized(self) {
        [[self allTasks] enumerateObjectsUsingBlock:^(NSURLSessionDataTask * _Nonnull task, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([task isKindOfClass:[NSURLSessionDataTask class]]
                && [task.currentRequest.URL.absoluteString hasSuffix:url]) {
                [task cancel];
                
                [[self allTasks] removeObject:task];
                return;
            }
        }];
    };
}

#pragma mark -- POST请求
/* 是否需要缓存数据 **/
+ (void)postRequestCache:(BOOL)isCache
                  URLStr:(NSString *)urlStr
                 withDic:(NSDictionary *)parameters
                 success:(SuccessBlock)success
                 failure:(ErrorBlock)failure {
    
    [[self alloc] requestWithUrl:urlStr parameters:parameters requsetType:RequestTypePost isCache:isCache imageKey:nil withData:nil  withDataArr:nil loadProgress:^(float progress)  {
        
    } success:^(NSDictionary *responseObject,NSString * msg) {
        success(responseObject,msg);
    } failure:^(NSString *errorInfo,NSString *status) {
        failure(errorInfo,status);
    }];
}

#pragma mark -- POST请求 不缓存数据
+ (void)postRequestURLStr:(NSString *)urlStr
                  withDic:(NSDictionary *)parameters
                  success:(SuccessBlock)success
                  failure:(ErrorBlock)failure{
    
    [self postRequestCache:NO  URLStr:urlStr withDic:parameters success:success failure:failure];
    
    //    [[self alloc] requestWithUrl:urlStr parameters:parameters requsetType:RequestTypePost isCache:NO imageKey:nil withData:nil withDataArr:nil loadProgress:^(float progress)  {
    //
    //    } success:^(NSDictionary *responseObject,NSString * msg) {
    //        success(responseObject,msg);
    //    } failure:^(NSString *errorInfo,NSString *status) {
    //        failure(errorInfo,status);
    //    }];
}
#pragma mark -- Put  不加缓存
/*!
 *  Put请求 不缓存数据
 *
 *  @param urlStr     url
 *  @param parameters post参数
 *  @param success    成功的回调
 *  @param failure    失败的回调
 */
+ (void)putRequestURLStr:(NSString *)urlStr
                  withDic:(NSDictionary *)parameters
                  success:(SuccessBlock)success
                 failure:(ErrorBlock)failure {
    
    [[self alloc] requestWithUrl:urlStr parameters:parameters requsetType:RequestTypePut isCache:NO imageKey:nil withData:nil  withDataArr:nil loadProgress:^(float progress)  {
        
    } success:^(NSDictionary *responseObject,NSString * msg) {
        success(responseObject,msg);
    } failure:^(NSString *errorInfo,NSString *status) {
        failure(errorInfo,status);
    }];
}

/*!
 *  DELETE请求 不缓存数据
 *
 *  @param urlStr     url
 *  @param parameters post参数
 *  @param success    成功的回调
 *  @param failure    失败的回调
 */
+ (void)deleteRequestURLStr:(NSString *)urlStr
                  withDic:(NSDictionary *)parameters
                  success:(SuccessBlock)success
                    failure:(ErrorBlock)failure {
    
    [[self alloc] requestWithUrl:urlStr parameters:parameters requsetType:RequestTypeDelete isCache:NO imageKey:nil withData:nil  withDataArr:nil loadProgress:^(float progress)  {
        
    } success:^(NSDictionary *responseObject,NSString * msg) {
        success(responseObject,msg);
    } failure:^(NSString *errorInfo,NSString *status) {
        failure(errorInfo,status);
    }];
}

#pragma mark -- POST请求 缓存数据



+ (void)postRequestCacheURLStr:(NSString *)urlStr
                       withDic:(NSDictionary *)parameters
                       success:(SuccessBlock)success
                       failure:(ErrorBlock)failure {
    
    [self postRequestCache:YES URLStr:urlStr withDic:parameters success:success failure:failure];
    
    //    [[self alloc] requestWithUrl:urlStr parameters:parameters requsetType:RequestTypePost isCache:YES imageKey:nil withData:nil  withDataArr:nil loadProgress:^(float progress)  {
    //
    //    } success:^(NSDictionary *responseObject,NSString * msg) {
    //        success(responseObject,msg);
    //    } failure:^(NSString *errorInfo,NSString *status) {
    //        failure(errorInfo,status);
    //    }];
}
#pragma mark -- GET请求 不缓存数据
+ (void)getRequestURLStr:(NSString *)urlStr
                 withDic:(NSDictionary *)parameters
                 success:(SuccessBlock)success
                 failure:(ErrorBlock)failure{
    [[self alloc] requestWithUrl:urlStr parameters:parameters requsetType:RequestTypeGet isCache:NO imageKey:nil withData:nil withDataArr:nil loadProgress:^(float progress)  {
        
    } success:^(NSDictionary *responseObject,NSString * msg) {
        success(responseObject,msg);
    } failure:^(NSString *errorInfo,NSString *status) {
        failure(errorInfo,status);
    }];
}
#pragma mark -- GET请求 缓存数据
+ (void)getRequestCacheURLStr:(NSString *)urlStr
                      withDic:(NSDictionary *)parameters
                      success:(SuccessBlock)success
                      failure:(ErrorBlock)failure{
    [[self alloc] requestWithUrl:urlStr parameters:parameters requsetType:RequestTypeGet isCache:YES  imageKey:nil withData:nil  withDataArr:nil loadProgress:^(float progress)  {
        
    } success:^(NSDictionary *responseObject,NSString * msg) {
        success(responseObject,msg);
    } failure:^(NSString *errorInfo,NSString *status) {
        failure(errorInfo,status);
    }];
}

#pragma mark -- 上传单个文件
+ (void)uploadDataWithURLStr:(NSString *)urlStr
                     withDic:(NSDictionary *)pasameters
                    imageKey:(NSString *)attach
                    withData:(NSData *)data
              uploadProgress:(LoadProgressBlock)loadProgress
                     success:(SuccessBlock)success
                     failure:(ErrorBlock)failure {
    
    [[self alloc] requestWithUrl:urlStr parameters:pasameters requsetType:RequestTypeUpLoadOne isCache:NO imageKey:attach withData:data withDataArr:nil loadProgress:^(float progress) {
        dispatch_async(dispatch_get_main_queue(), ^{
            
            if (loadProgress) {
                
                loadProgress(progress);
            }
        });
        
    } success:^(NSDictionary *responseObject,NSString * msg) {
        success(responseObject,msg);
    } failure:^(NSString *errorInfo,NSString *status) {
        failure(errorInfo,status);
    }];
}

/**
 *  上传视频 音频 图片
 *
 *  @param URLString   请求的链接
 *  @param parameters  请求的参数
 *  @param block       二进制文件的参数
 
 二进制 文件 的请求 要用到下面的方法
 （1）： 传入文件的路径
 [formData appendPartWithFileURL:[NSURL fileURLWithPath:mp4Path] name:@"Filedata" fileName:@"mp4Path.mp4" mimeType:@"application/octet-stream" error:nil];
 或者
 （2）：传入文件的data
 [formData appendPartWithFileData:data name:@"服务器接收的名字" fileName:@"自己给当前的文件取的名字" mimeType:@"application/octet-stream"];
 
 *  @param success     请求成功
 *  @param failure     请求失败
 *  @param uploadProgressBlock 请求的进度
 *
 *  @return AFHTTPRequestOperation的请求
 */

/*
 
 - (NSURLSessionDataTask *)POST:(NSString *)URLString
 parameters:(id)parameters
 constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
 progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
 success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
 failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
 
 **/

+ (NSURLSessionDataTask*)MMPost:(NSString *)URLString
                     parameters:(id)parameters
      constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
                       progress:( void (^)(NSProgress *  progress))uploadProgressBlock
                        success:(void (^)(NSURLSessionDataTask *operation, id responseObject))success
                        failure:(void (^)(NSURLSessionDataTask *operation, NSError *error))failure{
    
    AFHTTPSessionManager *manager = [MM_Http afManager];
    [MM_Http setOvertime:20 WithManage:manager];
    URLString = [MM_Http getFullPathWithPath:URLString];
    
    NSURLSessionDataTask *operation = [manager POST:URLString parameters:parameters constructingBodyWithBlock:block progress:^(NSProgress * _Nonnull uploadProgress) {
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            if (uploadProgressBlock) {
                
                uploadProgressBlock(uploadProgress);
            }
        });
        
    } success:success failure:failure];
    //    [operation setUploadProgressBlock:uploadBlock];
    
    return operation;
}

+ (AFHTTPSessionManager *)afManager {
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    manager.requestSerializer  = [AFHTTPRequestSerializer serializer];
    manager.requestSerializer = [AFJSONRequestSerializer serializer];

    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html",nil];

    return manager;
    
}

+ (void)setOvertime:(CGFloat)overtime WithManage:(AFHTTPSessionManager *)manager  {
    // 设置超时时间
    [manager.requestSerializer willChangeValueForKey:@"timeoutInterval"];
    manager.requestSerializer.timeoutInterval = overtime;
    [manager.requestSerializer didChangeValueForKey:@"timeoutInterval"];
    
//    manager.securityPolicy.validatesDomainName = NO;
    
    //请求heder
    [manager.requestSerializer setValue:[NSString stringWithFormat:@"Bearer %@",[MM_Cache shareMM_Cache].userModel.access_token] forHTTPHeaderField:@"Authorization"];
    [manager.requestSerializer setHTTPShouldHandleCookies:NO];
    [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
}

/**
 *  获得全路径
 *
 *  @param path 路径
 *
 *  @return 返回全路径
 */
+ (NSString *)getFullPathWithPath:(NSString *)path {
    
    path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    if(path &&![path hasPrefix:@"http://"]&&![path hasPrefix:@"https://"]){
        path=[NSString stringWithFormat:@"%@%@",SERVER_HOST,path];
    }
    return path;
}


#pragma mark -- 上传多个文件
+ (void)uploadDataWithURLStr:(NSString *)urlStr
                     withDic:(NSDictionary *)pasameters
                    imageKey:(NSString *)attach
                   withArray:(NSArray *)dataArr
              uploadProgress:(LoadProgressBlock)loadProgress
                     success:(SuccessBlock)success
                     failure:(ErrorBlock)failure {
    [[self alloc] requestWithUrl:urlStr parameters:pasameters requsetType:RequestTypeUpLoadMore isCache:NO imageKey:attach withData:nil withDataArr:dataArr loadProgress:^(float progress) {
        dispatch_async(dispatch_get_main_queue(), ^{
            
            if (loadProgress) {
                
                loadProgress(progress);
            }
        });
    } success:^(NSDictionary *responseObject,NSString * msg) {
        success(responseObject,msg);
    } failure:^(NSString *errorInfo,NSString *status) {
        failure(errorInfo,status);
    }];
}

#pragma mark -- 网络请求统一处理
- (void)requestWithUrl:(NSString *)url
            parameters:(NSDictionary *)parameters
           requsetType:(RequestType)requestType
               isCache:(BOOL)isCache
              imageKey:(NSString *)attach
              withData:(NSData *)data
           withDataArr:(NSArray *)dataArr
          loadProgress:(LoadProgressBlock)loadProgress
               success:(SuccessBlock)success
               failure:(ErrorBlock)failure {
    
    if (url.length == 0) {
        return;
    }
    
//    NSString *currentVersion = [JH_GlobalTool current_version];
    NSMutableDictionary *paraDic = [NSMutableDictionary dictionaryWithDictionary:parameters];
//    NSString *Authorization = [NSString stringWithFormat:@"Bearer %@",[MM_Cache shareMM_Cache].userModel.access_token];
////    NSString *token = [JH_UserManager sharedUserManager].token;
//    if (!paraDic[@"Authorization"] && Authorization) {
//        paraDic[@"Authorization"] = [NSString stringWithFormat:@"Bearer %@",[MM_Cache shareMM_Cache].userModel.access_token];
//    }
//    if (!paraDic[@"token"] && token) {
//        paraDic[@"token"] = token;
//    }
    parameters = paraDic;
    
    NSString *originUrl = url;
    if (!([url hasPrefix:@"http"]||[url hasPrefix:@"https"])) {
        
        url = [SERVER_HOST stringByAppendingString:url];
    }
    /* ios7 以后的的方法 把中文转化成=》UTF-8 编码 **/
    url = [url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; // ios7
    
    /* 获得缓存 的 url 来做数据库的唯一标示  **/
    NSString * cacheUrl = [MM_Http urlDictToStringWithUrlStr:url WithDict:parameters];
    MMLog(@"\n\n-网址--\n\n       %@--->     %@\n\n-网址--\n\n",(requestType ==RequestTypeGet)?@"Get":@"POST",cacheUrl);
     
    __block NSData * cacheData = nil;
    /* 是否存在，有的话先显示出来 **/
//    if (isCache && [JH_UserManager sharedUserManager].token.integerValue > 0) {
    
    if (isCache) {
        
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        
        [[MM_DB shareManager].netWorkTableTool cachedDataWithUrl:cacheUrl cacheDataBlock:^(NSData * data) {
            
            if(data.length > 0){
                
                cacheData = data;
                [self parseDataWithRequestData:cacheUrl data:data Success:^(NSDictionary *requestDic, NSString *msg) {
                    success(requestDic,msg);
                } failure:^(NSString *errorInfo, NSString *status) {
                    failure(errorInfo,status);
                }];
            }
            dispatch_semaphore_signal(sema);
        }];
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    }
    
    //请求前网络检查
    AFHTTPSessionManager *manager = [MM_Http afManager];
    // 设置超时时间
    [MM_Http setOvertime:10 WithManage:manager];

    NSURLSessionDataTask * op;
    
    
    /*
     * 这里 不应该 用 if 判断
     * 而应该用 if  ,else if
     * 因为只能某种存在 就直接返回
     **/
    if (requestType == RequestTypeGet) {
        
        op = [manager GET:url parameters:parameters progress:nil success:^(NSURLSessionDataTask *operation, id responseObject) {
            
            [[[self class] allTasks] removeObject:operation];
            [self dealwithResponseObject:responseObject cacheUrl:cacheUrl cacheData:cacheData isCache:isCache success:^(NSDictionary *responseObject,NSString * msg) {
                success(responseObject,msg);
            } failure:^(NSString *errorInfo,NSString *status) {
                failure(errorInfo,status);
            }];
        } failure:^(NSURLSessionDataTask *operation, NSError *error) {
            
            [[[self class] allTasks] removeObject:operation];
            dispatch_async(dispatch_get_main_queue(), ^{
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;// 关闭网络指示器
            });
            
            MMLog(@"%@", [NSString stringWithFormat:@"Error: %@ /n 接口: %@", [error localizedDescription], originUrl]);
            
            if ([[error localizedDescription] containsString:@"401"]) {
                
                UIViewController *rootVc = [UIApplication sharedApplication].delegate.window.rootViewController;
                UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"会话登录过期,请重新登录!" preferredStyle:UIAlertControllerStyleAlert];
                UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *_Nonnull action) {
                    
                    [[MM_Cache shareMM_Cache] removeAllCustomInfo];
                    [MMNotificationCenter postNotificationName:MM_LogOutSuccessfully object:nil];
                }];
                [alertController addAction:okAction];
                [rootVc presentViewController:alertController animated:YES completion:nil];
            }
            
            failure([self returnServeErrorWithError:error],@"0");
            
        }];
        
    } else if (requestType == RequestTypePost) {
        
        op = [manager POST:url parameters:parameters progress:nil success:^(NSURLSessionDataTask *operation, id responseObject) {
            
            [[[self class] allTasks] removeObject:operation];
            [self dealwithResponseObject:responseObject cacheUrl:cacheUrl cacheData:cacheData isCache:isCache success:^(NSDictionary *responseObject,NSString * msg) {
                
                success(responseObject,msg);
            } failure:^(NSString *errorInfo,NSString *status) {
                
                failure(errorInfo,status);
            }];
        } failure:^(NSURLSessionDataTask *operation, NSError *error) {
            
            [[[self class] allTasks] removeObject:operation];
            dispatch_async(dispatch_get_main_queue(), ^{
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;// 关闭网络指示器
            });
            MMLog(@"%@", [NSString stringWithFormat:@"Error: %@ /n 接口: %@", [error localizedDescription], originUrl]);
            
            if ([[error localizedDescription] containsString:@"401"]) {
                
                UIViewController *rootVc = [UIApplication sharedApplication].delegate.window.rootViewController;
                UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"会话登录过期,请重新登录!" preferredStyle:UIAlertControllerStyleAlert];
                UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *_Nonnull action) {
                    
                    [[MM_Cache shareMM_Cache] removeAllCustomInfo];
                    [MMNotificationCenter postNotificationName:MM_LogOutSuccessfully object:nil];
                }];
                [alertController addAction:okAction];
                [rootVc presentViewController:alertController animated:YES completion:nil];
            }
            
            failure([self returnServeErrorWithError:error], @"0");
        }];
        
    }else if (requestType == RequestTypePut) {
        
        op = [manager PUT:url parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            
            [self dealwithResponseObject:responseObject cacheUrl:cacheUrl cacheData:cacheData isCache:isCache success:^(NSDictionary *responseObject,NSString * msg) {
                
                success(responseObject,msg);
            } failure:^(NSString *errorInfo,NSString *status) {
                
                failure(errorInfo,status);
            }];

        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            
            dispatch_async(dispatch_get_main_queue(), ^{
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;// 关闭网络指示器
            });
            MMLog(@"%@", [NSString stringWithFormat:@"Error: %@ /n 接口: %@", [error localizedDescription], originUrl]);
            
            if ([[error localizedDescription] containsString:@"401"]) {
                
                UIViewController *rootVc = [UIApplication sharedApplication].delegate.window.rootViewController;
                UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"会话登录过期,请重新登录!" preferredStyle:UIAlertControllerStyleAlert];
                UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *_Nonnull action) {
                    
                    [[MM_Cache shareMM_Cache] removeAllCustomInfo];
                    [MMNotificationCenter postNotificationName:MM_LogOutSuccessfully object:nil];
                }];
                [alertController addAction:okAction];
                [rootVc presentViewController:alertController animated:YES completion:nil];
            }
            
            failure([self returnServeErrorWithError:error], @"0");

        }];
                
    }else if (requestType == RequestTypeDelete) {
        
        op = [manager DELETE:url parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            
            [self dealwithResponseObject:responseObject cacheUrl:cacheUrl cacheData:cacheData isCache:isCache success:^(NSDictionary *responseObject,NSString * msg) {
                
                success(responseObject,msg);
            } failure:^(NSString *errorInfo,NSString *status) {
                
                failure(errorInfo,status);
            }];
            
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            
            dispatch_async(dispatch_get_main_queue(), ^{
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;// 关闭网络指示器
            });
            MMLog(@"%@", [NSString stringWithFormat:@"Error: %@ /n 接口: %@", [error localizedDescription], originUrl]);
            
            if ([[error localizedDescription] containsString:@"401"]) {
                
                UIViewController *rootVc = [UIApplication sharedApplication].delegate.window.rootViewController;
                UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"会话登录过期,请重新登录!" preferredStyle:UIAlertControllerStyleAlert];
                UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *_Nonnull action) {
                    
                    [[MM_Cache shareMM_Cache] removeAllCustomInfo];
                    [MMNotificationCenter postNotificationName:MM_LogOutSuccessfully object:nil];
                }];
                [alertController addAction:okAction];
                [rootVc presentViewController:alertController animated:YES completion:nil];
            }
            
            failure([self returnServeErrorWithError:error], @"0");

        }];
        
    } else if (requestType == RequestTypeUpLoadOne) {
        
        op =  [manager POST:url parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
            // 给上传的文件命名
            NSTimeInterval timeInterval = [[NSDate date] timeIntervalSince1970];
            NSString * fileName =[NSString stringWithFormat:@"%@.png",@(timeInterval)];
            [formData appendPartWithFileData:data name:attach fileName:fileName mimeType:@"image/jpeg"];
            
        } progress:nil success:^(NSURLSessionDataTask *operation, id responseObject) {
            
            [[[self class] allTasks] removeObject:operation];
            [self dealwithResponseObject:responseObject cacheUrl:cacheUrl cacheData:cacheData isCache:NO success:^(NSDictionary *responseObject,NSString * msg) {
                success(responseObject,msg);
            } failure:^(NSString *errorInfo,NSString *status) {
                failure(errorInfo,status);
            }];
        } failure:^(NSURLSessionDataTask *operation, NSError *error) {
            
            [[[self class] allTasks] removeObject:operation];
            dispatch_async(dispatch_get_main_queue(), ^{
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;// 关闭网络指示器
            });
            MMLog(@"%@", [NSString stringWithFormat:@"Error: %@ /n 接口: %@", [error localizedDescription], originUrl]);
            
            if ([[error localizedDescription] containsString:@"401"]) {
                
                UIViewController *rootVc = [UIApplication sharedApplication].delegate.window.rootViewController;
                UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"会话登录过期,请重新登录!" preferredStyle:UIAlertControllerStyleAlert];
                UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *_Nonnull action) {
                    
                    [[MM_Cache shareMM_Cache] removeAllCustomInfo];
                    [MMNotificationCenter postNotificationName:MM_LogOutSuccessfully object:nil];
                }];
                [alertController addAction:okAction];
                [rootVc presentViewController:alertController animated:YES completion:nil];
            }
            failure([error localizedDescription], @"0");
        }];
        
    } else if (requestType == RequestTypeUpLoadMore) {
        
        /*
         * 关于这个多图上传 ，我不建议这样做，这样做事 把整个图上传成功后才能
         * 否则如果只有某一张图片 不行了，整个上传就不行了
         **/
        
        op =  [manager POST:url parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
            // 上传多张图片
            for(NSInteger i = 0; i < dataArr.count; i++) {
                
                //取出单张图片二进制数据
                NSData * imageData = dataArr[i];
                NSString *Name = [NSString stringWithFormat:@"%@%@", attach,@(i+1)];
                NSString *fileName = [NSString stringWithFormat:@"%@.png", Name];
                [formData appendPartWithFileData:imageData name:Name fileName:fileName mimeType:@"image/png"];
            }
        } progress:nil success:^(NSURLSessionDataTask *operation, id responseObject) {
            
            [[[self class] allTasks] removeObject:operation];
            [self dealwithResponseObject:responseObject cacheUrl:cacheUrl cacheData:cacheData isCache:NO success:^(NSDictionary *responseObject,NSString * msg) {
                success(responseObject,msg);
            } failure:^(NSString *errorInfo,NSString *status) {
                failure(errorInfo,status);
            }];
            
        } failure:^(NSURLSessionDataTask *operation, NSError *error) {
            
            [[[self class] allTasks] removeObject:operation];
            dispatch_async(dispatch_get_main_queue(), ^{
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;// 关闭网络指示器
            });
            MMLog(@"%@", [NSString stringWithFormat:@"Error: %@ /n 接口: %@", [error localizedDescription], originUrl]);
            
            if ([[error localizedDescription] containsString:@"401"]) {
                
                UIViewController *rootVc = [UIApplication sharedApplication].delegate.window.rootViewController;
                UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"会话登录过期,请重新登录!" preferredStyle:UIAlertControllerStyleAlert];
                UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *_Nonnull action) {
                    
                    [[MM_Cache shareMM_Cache] removeAllCustomInfo];
                    [MMNotificationCenter postNotificationName:MM_LogOutSuccessfully object:nil];
                }];
                [alertController addAction:okAction];
                [rootVc presentViewController:alertController animated:YES completion:nil];
            }
            failure([error localizedDescription], @"0");
        }];
    }
    
    if (op) {
        [[[self class] allTasks] addObject:op];
    }
}

#pragma mark -- 统一处理请求到得数据
/*!
 *  @param responseData 网络请求的数据
 *  @param cacheUrl       缓存的url标识
 *  @param cacheData      缓存的数据
 *  @param isCache        是否需要缓存
 */
- (void)dealwithResponseObject:(NSData *)responseData
                      cacheUrl:(NSString *)cacheUrl
                     cacheData:(NSData *)cacheData
                       isCache:(BOOL)isCache
                       success:(SuccessBlock)success
                       failure:(ErrorBlock)failure {
    
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;// 关闭网络指示器
    });
    
    //    NSString * dataString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
    //    dataString = [self deleteSpecialCodeWithStr:dataString];
    //    NSData *requstData=[dataString dataUsingEncoding:NSUTF8StringEncoding];
    NSData *requstData = responseData;
    
    if (isCache) {/**更新缓存数据*/
        
        [[MM_DB shareManager].netWorkTableTool saveData:requstData url:cacheUrl];
    }
    
    if (!isCache || ![cacheData isEqual:requstData]) {
        
        [self parseDataWithRequestData:cacheUrl data:requstData Success:^(NSDictionary *requestDic, NSString *msg) {
            success(requestDic,msg);
        } failure:^(NSString *errorInfo, NSString *status) {
            failure(errorInfo, status);
        }];
    }
}
#pragma mark --根据返回的数据进行统一的格式处理  ----requestData 网络或者是缓存的数据----

/*
 * 解析请求返回的data 数据
 * 其实我是不建议 把 data 转换成 字典
 * 原因：因为后台返回的数据可能是其他类型，不利于扩展数据类型
 **/
- (void)parseDataWithRequestData:(NSString *)url data:(NSData *)requestData Success:(SuccessBlock)success failure:(ErrorBlock)failure {
    
    id myResult = [NSJSONSerialization JSONObjectWithData:requestData options:NSJSONReadingMutableContainers error:nil];
    
    //返回数据是个字典
    if ([myResult isKindOfClass:[NSDictionary  class]]) {
        
        NSDictionary *  requestDic = (NSDictionary *)myResult;
        NSString * codeStr = [requestDic[@"code"] description];
        
        if ([codeStr isEqualToString:@"200"]) {
            
            if ([requestDic[@"data"] isKindOfClass:[NSDictionary class]]) {  //data是字典
                
                success(requestDic[@"data"],[requestDic[@"errorMessage"] description]);
            } else if ([requestDic[@"data"] isKindOfClass:[NSArray class]]) { //data是数组
                success(requestDic, requestDic[@"errorMessage"]);
            } else {  //data可能是null
                if ([requestDic[@"data"] isKindOfClass:[NSNull class]] || requestDic[@"data"] == nil) {
                    success([NSDictionary dictionary], [requestDic[@"errorMessage"] description]);
                } else {
                    success(requestDic, [requestDic[@"errorMessage"] description]);
                }
            }
        }else{
            
            /* requestDic[@"data"] 返回的是 数组 类型 **/
            id errorMessage = nil;
            NSString * tmpMessage = [requestDic[@"errorMessage"] description];
            NSArray *  tmpData    = requestDic[@"data"];
            if ([tmpMessage length]) {
                errorMessage = tmpMessage;
            }
            if ([tmpData isKindOfClass:[NSArray class]]) {
                if (tmpData.count) {
                    NSString * firstData = tmpData.firstObject;
                    if ([firstData isKindOfClass:[NSString class]]) {
                        errorMessage = firstData;
                    }
                }
            }
            NSString * message = [NSString stringWithFormat:@"%@",errorMessage];
            /* 因为后台的错误信息 是用 Unicode 码，所以必须转换 Unicode 编码 **/
            failure([MM_Http decodeUnicode:message]?:message, [requestDic[@"status"] description]);
        }
        
    }else if ([myResult isKindOfClass:[NSArray class]]) {
        
        NSArray * requestArr = (NSArray *)myResult;
        success(requestArr[0], @"成功");
    }
}

+ (NSString *)decodeUnicode:(NSString *)message {
    
    /* 1.把字符串 中 含有 \u => \U **/
    NSString *tempStr1 = [message stringByReplacingOccurrencesOfString:@"\\u"withString:@"\\U"];
    if (tempStr1.length == 0) {
        return nil;
    }
    /* 2.把字符串 中 含有 " => \" **/
    NSString *tempStr2 = [tempStr1 stringByReplacingOccurrencesOfString:@"\""withString:@"\\\""];
    /* 3.字符串 中 前面放入 " ,后面也放入 " **/
    NSString *tempStr3 = [[@"\""stringByAppendingString:tempStr2] stringByAppendingString:@"\""];
    
    NSData *tempData = [tempStr3 dataUsingEncoding:NSUTF8StringEncoding];
    NSString* returnStr = [NSPropertyListSerialization propertyListFromData:tempData
                                                           mutabilityOption:NSPropertyListImmutable
                                                                     format:NULL
                                                           errorDescription:NULL];
    return [returnStr stringByReplacingOccurrencesOfString:@"\\r\\n"withString:@"\n"];
}

#pragma mark -- 数据库实例
static FMDatabase *_db;
+ (void)initialize{
    
    
    //    NSString * bundleName =[[NSBundle mainBundle] infoDictionary][(NSString *)kCFBundleNameKey];
    //    NSString *dbName=[NSString stringWithFormat:@"%@%@",bundleName,@".sqlite"];
    //    NSString *filename = [KURLCachePath stringByAppendingPathComponent:dbName];
    //    _db = [FMDatabase databaseWithPath:filename];
    //    if ([_db open]) {
    //        BOOL res = [_db tableExists:@"MCData"];
    //        if (!res) {
    //            // 4.创表
    //            [_db executeUpdate:@"CREATE TABLE IF NOT EXISTS MCData (id integer PRIMARY KEY AUTOINCREMENT, url text NOT NULL, data blob NOT NULL,savetime date);"];
    //            //            JHLog(@"\n\n---%@----\n\n",result?@"成功创表":@"创表失败");
    //        }
    //    }
    //    [_db close];
}
//#pragma mark --通过请求参数去数据库中加载对应的数据
//- (NSData *)cachedDataWithUrl:(NSString *)url{
//    NSData * data = [[NSData alloc]init];
//    [_db open];
//    FMResultSet *resultSet = nil;
//    resultSet = [_db executeQuery:@"SELECT * FROM MCData WHERE url = ?", url];
//    // 遍历查询结果
//    while (resultSet.next) {
//        NSDate *  time = [resultSet dateForColumn:@"savetime"];
//        NSTimeInterval timeInterval = -[time timeIntervalSinceNow];
//        if(timeInterval > cacheTime &&  cacheTime!= 0){
//            //            JHLog(@"\n\n     %@     \n\n",@"缓存的数据过期了");
//            //            [JH_FileTool removeAllCustomPath];
//        }else{
//            data = [resultSet objectForColumnName:@"data"];
//        }
//    }
//    [_db close];
//    return data;
//}
//#pragma mark -- 缓存数据到数据库中
//- (void)saveData:(NSData *)data url:(NSString *)url{
//    [_db open];
//    FMResultSet *rs = [_db executeQuery:@"select * from MCData where url = ?",url];
//    if([rs next]){
//        [_db executeUpdate: @"update MCData set data =?,savetime =? where url = ?",data,[NSDate date],url];
//        //        JHLog(@"\n\n%@     %@\n\n",url,res?@"数据更新成功":@"数据更新失败");
//    }
//    else{
//        [_db executeUpdate:@"INSERT INTO MCData (url,data,savetime) VALUES (?,?,?);",url, data,[NSDate date]];
//        //        JHLog(@"\n\n%@     %@\n\n",url,res?@"数据插入成功":@"数据插入失败");
//    }
//    [_db close];
//}
//


#pragma mark  请求前统一处理：如果是没有网络，则不论是GET请求还是POST请求，均无需继续处理

- (BOOL)requestBeforeCheckNetWork {
    
    struct sockaddr zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sa_len = sizeof(zeroAddress);
    zeroAddress.sa_family = AF_INET;
    SCNetworkReachabilityRef defaultRouteReachability =
    SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
    SCNetworkReachabilityFlags flags;
    BOOL didRetrieveFlags =
    SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
    CFRelease(defaultRouteReachability);
    if (!didRetrieveFlags) {
        printf("Error. Count not recover network reachability flags\n");
        return NO;
    }
    BOOL isReachable = flags & kSCNetworkFlagsReachable;
    BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
    BOOL isNetworkEnable  =(isReachable && !needsConnection) ? YES : NO;
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIApplication sharedApplication].networkActivityIndicatorVisible =isNetworkEnable;/*  网络指示器的状态： 有网络 ： 开  没有网络： 关  */
    });
    return isNetworkEnable;
}
#pragma mark ---   计算一共缓存的数据的大小
//+ (NSString *)cacheSize{
//    NSFileManager *mgr = [NSFileManager defaultManager];
//    NSArray *subpaths = [mgr subpathsAtPath:cachePath];
//    long long ttotalSize = 0;
//    for (NSString *subpath in subpaths) {
//        NSString *fullpath = [cachePath stringByAppendingPathComponent:subpath];
//        BOOL dir = NO;
//        [mgr fileExistsAtPath:fullpath isDirectory:&dir];
//        if (dir == NO) {// 文件
//            ttotalSize += [[mgr attributesOfItemAtPath:fullpath error:nil][NSFileSize] longLongValue];
//        }
//    }//  M
//    ttotalSize = ttotalSize/1024;
//    return ttotalSize<1024?[NSString stringWithFormat:@"%lld KB",ttotalSize]:[NSString stringWithFormat:@"%.2lld MB",ttotalSize/1024];
//}
/**
 *  获取文件大小
 */
+ (unsigned long long)fileSizeForPath:(NSString *)path {
    
    signed long long fileSize = 0;
    NSFileManager *fileManager = [[NSFileManager alloc] init];
    if ([fileManager fileExistsAtPath:path]) {
        
        NSError *error = nil;
        NSDictionary *fileDict = [fileManager attributesOfItemAtPath:path error:&error];
        if (!error && fileDict) {
            
            fileSize = [fileDict fileSize];
        }
    }
    return fileSize;
}
#pragma mark ---   清空缓存的数据
+ (void)deleateCache {
    
    //    NSFileManager *mgr = [NSFileManager defaultManager];
    //    [mgr removeItemAtPath:KCachePath error:nil];
    [MM_FileTool removeAllCustomPath];
}
#pragma mark -- 拼接 Get 请求的网址
+ (NSString *)urlDictToStringWithUrlStr:(NSString *)urlStr WithDict:(NSDictionary *)parameters {
    
    if (!([urlStr hasPrefix:@"http"]||[urlStr hasPrefix:@"https"])) {
        
        urlStr = [SERVER_HOST stringByAppendingString:urlStr];
    }
    if (!parameters) {
        return urlStr;
    }
    NSMutableArray *parts = [NSMutableArray array];
    [parameters enumerateKeysAndObjectsUsingBlock:^(id key, id<NSObject> obj, BOOL *stop) {
        
        //NSString *encodedKey = [key stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
        NSString *encodedValue = [obj.description stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
        NSString *part = [NSString stringWithFormat: @"%@=%@", key, encodedValue];
        [parts addObject: part];
    }];
    NSString *queryString = [parts componentsJoinedByString: @"&"];
    if (queryString.length == 0) {
        
        return urlStr;
    }else {
        
        return [NSString stringWithFormat:@"%@?%@",urlStr,queryString];
    }
    //    queryString =  queryString.length ? [NSString stringWithFormat:@"%@", queryString] : @"";
    //    NSString * pathStr =[NSString stringWithFormat:@"%@?%@",urlStr,queryString];
    //    return pathStr;
}
#pragma mark -- 处理json格式的字符串中的换行符、回车符
- (NSString *)deleteSpecialCodeWithStr:(NSString *)str {
    
    NSString *string = [str stringByReplacingOccurrencesOfString:@"\r" withString:@""];
    //    string = [string stringByReplacingOccurrencesOfString:@"\n" withString:@""];
    //    string = [string stringByReplacingOccurrencesOfString:@"\n" withString:@""];
    string = [string stringByReplacingOccurrencesOfString:@"\t" withString:@""];
    //    string = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
    //    string = [string stringByReplacingOccurrencesOfString:@"(" withString:@""];
    //    string = [string stringByReplacingOccurrencesOfString:@")" withString:@""];
    return string;
}


#pragma mark - 实例方法

- (unsigned long long)fileSizeForPath:(NSString *)path {
    
    signed long long fileSize = 0;
    
    NSFileManager *fileManager = [[NSFileManager alloc] init];
    
    if ([fileManager fileExistsAtPath:path]) {
        
        NSError *error = nil;
        
        NSDictionary *fileDict = [fileManager attributesOfItemAtPath:path error:&error];
        
        if (!error && fileDict) {
            
            fileSize = [fileDict fileSize];
        }
    }
    
    return fileSize;
}
/**
 *  获得图片全路径
 *
 *  @param path 路径
 *
 *  @return 返回全路径
 */
+ (NSString *)getImageFullPathWithPath:(NSString *)path {
    
    if ([path isKindOfClass:[NSNull class]]) {
        path =  @"";
    }
    if (path && path.length > 0) {
        //    path = @"/img/2017-12-05_11:37:15:342.png";
        
        if (!([path hasPrefix:@"http://"] || [path hasPrefix:@"https://"])) {
            
            path = [SERVER_IMG stringByAppendingString:path];
        }
    }
    
    //去除前后空格
    NSCharacterSet  *set = [NSCharacterSet whitespaceCharacterSet];
    path = [path stringByTrimmingCharactersInSet:set];
    
    return path;
}
+ (NSURL *)getImgUrlFullPathWithStr:(NSString *)urlStr {
    
    NSString * str = [self getImageFullPathWithPath:urlStr];
    if (str.length == 0) {
        /* 返回一个不会崩溃的 URL **/
        return [NSURL URLWithString:@"https://123"];
    }
    return [NSURL URLWithString:str];
}
@end
